#include <stdlib.h>
#include <stdio.h>
#include <string.h>


/*****************************************
**  Zone de déclaration des constantes  **
*****************************************/
#define Fic_Regles "Regles"	//a modifier si besoin
#define Fic_Faits "Faits"	//a modifier si besoin	
#define MAXSIZE 20
#define False 0
#define True 1
	

/*****************************************
**  Zone de déclaration des structures  **
*****************************************/
typedef struct CONDITION
{
	char cond[MAXSIZE];
	int valid;
	struct CONDITION *suiv; 
} ST_COND;

typedef struct FAITS
{
	char fait[MAXSIZE];
	struct FAITS *suiv; 
} ST_FAITS;

typedef struct RESULTAT
{
	char res[MAXSIZE];
	int valid;
	int nb_cond;
	int nb_cond_valid;
	ST_COND* TeteListCond;
	struct RESULTAT *suiv;
} ST_RES;


/*****************************************
**  Zone de déclaration des Prototypes  **
*****************************************/
FILE* OuvrirFic(char* NomFic, char* mode);
void LireBases(char indic, FILE* fp);
void AfficherListe(char indic);
void FreeListe(char indic);
void FermerFichier(FILE* fp);
ST_COND* Creer_MaillonCond(ST_COND* pt_tete, char* str);
ST_RES* Creer_MaillonRes(ST_RES* pt_tete, ST_COND* Tete_Cond, char* str);
ST_FAITS* Creer_MaillonFaits(ST_FAITS* pt_tete, char* str);

void ParcoursConditions(char *str, ST_RES *res,ST_COND *pt_Tete);
void ValideCondition(ST_RES *resultat,ST_COND *condition);
void ParcoursResultats(char *str, ST_RES *pt_Tete);
void ValideResultat(ST_RES *resultat);
void BoucleValidation(void);
void ChainageAvant(void);

/*************************************************
**  Zone de déclaration des variables globales  **
*************************************************/
ST_RES *Tete_Res=NULL;
ST_FAITS *Tete_Faits=NULL;


/**************************
**  Programme principal  **
**************************/
int main(void)
{
	FILE *fp=NULL;
	
	printf("\n----------[ Debut du Programme : ]-----------------\n\n");
	
	fp=OuvrirFic(Fic_Regles,"r");
	if(fp!=NULL)
	{
		LireBases('R',fp);
		FermerFichier(fp);
		AfficherListe('R');
	}
	
	fp=OuvrirFic(Fic_Faits,"r");
	if(fp!=NULL)
	{
		LireBases('F',fp);
		FermerFichier(fp);
		AfficherListe('F');
	}
	
	printf("\n----------[ Après Chainage Avant : ]---------------\n\n");
	ChainageAvant();
	AfficherListe('F');
	AfficherListe('R');
	
	FreeListe('R');
	FreeListe('F');
	return 0;
}

/***********************************************************************
**  [Fonction LireBases]					      **
**    Lit les fichiers de bases et les transforme en listes chainées  **
**    selon le type indiqué par indic ("r"=regles / "f"=faits)	      **
***********************************************************************/
void LireBases(char indic, FILE* fp)
{
	int flag=0;
	char mot[MAXSIZE];
	ST_COND *Tete_Cond=NULL;
	memset(mot,0,MAXSIZE*sizeof(char));
	
	if(indic=='f' || indic=='F')
	{
		while((fscanf(fp," %s", mot))!=EOF) //fscanf lit while(mot!=' ')
		{   
			if(mot[(strlen(mot)-1)]==';')
				mot[(strlen(mot)-1)]='\0';
			Tete_Faits=Creer_MaillonFaits(Tete_Faits,mot);		
		}
	}
	else if(indic=='r' || indic=='R')
	{
		while((fscanf(fp," %s", mot))!=EOF) //fscanf lit while(mot!=' ')
		{   
			if(!strcmp(mot,"->"))
				flag=1;
		
			if(flag==0)
				Tete_Cond=Creer_MaillonCond(Tete_Cond,mot);	
			else
			{
				if((fscanf(fp," %s", mot))!=EOF)
				{
					if(mot[(strlen(mot)-1)]==';')
						mot[(strlen(mot)-1)]='\0';
					Tete_Res=Creer_MaillonRes(Tete_Res,Tete_Cond,mot);
				}
				flag=0;
				Tete_Cond=NULL;
			}		
		}
	}
}

/******************************************************************
**  [Fonction Creer_MaillonCond]			         **
**    Créer le maillon pour une condition dans la liste chainée  **
**    des regles  					         **
******************************************************************/
ST_COND* Creer_MaillonCond(ST_COND* pt_tete, char* str)
{  
	ST_COND *new=NULL, *tmp=NULL;
	
	new=(ST_COND*)malloc(sizeof(ST_COND));
	memset(new->cond,0,MAXSIZE*sizeof(char));
	strcpy(new->cond, str);
	new->valid=False;
	new->suiv=NULL;
	
	if(pt_tete==NULL){ 
		//si liste vide ajout en tete
		new->suiv=pt_tete;
		pt_tete=new;
	}
	else{ 
		//sinon ajout en fin
		tmp=pt_tete;
		while(tmp->suiv!=NULL)
			tmp=tmp->suiv;
		
		tmp->suiv=new;
	}
	return pt_tete;
}

/****************************************************************
**  [Fonction Creer_MaillonRes]				       **
**    Créer le maillon pour un résultat dans la liste chainée  **
**    des regles  					       **
****************************************************************/
ST_RES* Creer_MaillonRes(ST_RES* pt_tete, ST_COND* Tete_Cond, char* str)
{  
	ST_RES *new=NULL, *tmp=NULL;
	ST_COND *tmp2=NULL;
	int cptr=0;
	
	new=(ST_RES*)malloc(sizeof(ST_RES));
	memset(new->res,0,MAXSIZE*sizeof(char));
	strcpy(new->res, str);
	new->valid=False;
	new->nb_cond_valid=0;
	new->suiv=NULL;
	new->TeteListCond=Tete_Cond;
	  tmp2=Tete_Cond;
	  while(tmp2!=NULL){
		cptr++;
		tmp2=tmp2->suiv;
	  }
	new->nb_cond=cptr;
	
	if(pt_tete==NULL){
		//si liste vide ajout en tete
		new->suiv=pt_tete;
		pt_tete=new;
	}
	else {
		//sinon ajout en fin
		tmp=pt_tete;
		while(tmp->suiv!=NULL)
			tmp=tmp->suiv;
		
		tmp->suiv=new;
	}
	return pt_tete;
}

/************************************************************
**  [Fonction Creer_MaillonFaits]			   **
**    Créer le maillon pour un fait dans la liste chainée  **
**    des faits  					   **
************************************************************/
ST_FAITS* Creer_MaillonFaits(ST_FAITS* pt_tete, char* str)
{  
	ST_FAITS *new=NULL, *tmp=NULL;
	int flag=0;
	
	new=(ST_FAITS*)malloc(sizeof(ST_FAITS));
	memset(new->fait,0,MAXSIZE*sizeof(char));
	strcpy(new->fait, str);
	new->suiv=NULL;
	
	if(pt_tete==NULL){
		//si liste vide ajout en tete
		new->suiv=pt_tete;
		pt_tete=new;
	}
	else {
		//sinon ajout en fin
		tmp=pt_tete;
		while(tmp->suiv!=NULL)
		{
			if(!strcmp(tmp->fait,str))
			{
				flag++;
			}
			tmp=tmp->suiv;
		}
		if(flag==0)
			tmp->suiv=new;
	}
	return pt_tete;
}

/*********************************************************
**  [Fonction OuvrirFic]				**
**    Ouvre le fichier passé en paramètre dans le mode	**
**    spécifié en paramètre par la variable mode	**
*********************************************************/
FILE* OuvrirFic(char* NomFic,char* mode)
{
	FILE* f=NULL;
	if ((f = fopen(NomFic, mode)) == NULL)
	{
		printf("Erreur d'ouverture du fichier %s !\n",NomFic);
		return NULL;
		//exit(qqch) ??
	}
	else
		return f;
}

/********************************************
**  [Fonction FermerFichier]		   **
**    Ferme le fichier passé en paramètre  **
********************************************/
void FermerFichier(FILE* fp)
{
	if(fclose(fp))
		printf("Erreur fermeture\n");	
}

/*********************************************************
**  [Fonction FreeListeRegles]		   		**
**    Supprime tous les maillons de la liste chainée    **
**    indiquée par indic ("R"=Regles / "F"=Faits)       **
*********************************************************/
void FreeListe(char indic)
{
	ST_RES* tmpR=Tete_Res;
	ST_RES* tmpR2=NULL;
	ST_COND* tmpC=Tete_Res->TeteListCond;
	ST_COND* tmpC2=NULL;
	ST_FAITS* tmp=Tete_Faits;
	ST_FAITS* tmp2=NULL;
	
	if(indic=='R' || indic=='r')
	{
		while(tmpR!=NULL){
			tmpR2=tmpR->suiv;
			while(tmpC!=NULL){
				tmpC2=tmpC->suiv;
				free(tmpC);
				tmpC=tmpC2;
			}
			free(tmpR);
			tmpR=tmpR2;
		}
	}
	else if(indic=='F' || indic=='f')
	{
		while(tmp!=NULL){
			tmp2=tmp->suiv;
			free(tmp);
			tmp=tmp2;
		}
	}
}

/********************************************************
**  [Fonction AfficherListe]		   	       **
**    Affiche tous les maillons de la liste chainée    **
**    indiquée par indic ("R"=Regles / "F"=Faits)      **
********************************************************/
void AfficherListe(char indic)
{
	ST_RES *R=NULL;
	ST_COND *C=NULL;
	ST_FAITS *F=NULL;
	
	if(indic=='R' || indic=='r')
	{
		printf(">AFFICHAGE LISTE REGLES\n");
		R=Tete_Res;
		printf(" -Ex:\n  [RES1: Valide(0\\1)/Nb_cond/Nb_cond_valid.]--{COND1: valid.(0\\1)}-{etc}\n\n");
		while(R!=NULL)
		{
			C=R->TeteListCond;
			printf("  [%s:%d/%d/%d]--",R->res,R->valid,R->nb_cond,R->nb_cond_valid);
			while(C!=NULL)
			{
				printf("{%s:%d}-",C->cond,C->valid);
				C=C->suiv;
			}
			printf("{NULL}\n");
			R=R->suiv;
		}
		printf("  [NULL]\n");
	}
	else if(indic=='F' || indic=='f')
	{
		printf(">AFFICHAGE LISTE FAITS\n");
		F=Tete_Faits;
		printf("   ");
		while(F!=NULL)
		{
			printf("[%s]-",F->fait);
			F=F->suiv;
		}
		printf("[NULL]\n");
	}
	printf("\n");
}

/*/////////////////////////////////////////////////////////////////////////////////////////////////
//                         Début de la partie "chainage avant"                                   //
\\         voir fichier "ChngAv.c" qui reprend les fonctions ci-dessous pour makefile            \\
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

/**************************************************
**  [Fonction ChainageAvant]                     **
**    Valide le resultat si celui-ci est dans    **
**    les faits                                  **
**************************************************/
void ChainageAvant(void)
{
	ST_FAITS *Fcourant=Tete_Faits;
	
	while(Fcourant!=NULL)
	{
		ParcoursResultats(Fcourant->fait,Tete_Res);
		BoucleValidation();
		Fcourant=Fcourant->suiv;
	}
}


/******************************************************
**  [Fonction ParcoursConditions]                    **
**    Parcours la liste chainée des conditions pour  **
**    un résultat donné et cherche les maillons      **
**    correspondant au fait "actuel"                 **
******************************************************/
void ParcoursConditions(char *str, ST_RES *res,ST_COND *pt_Tete)
{
	ST_COND *courant=pt_Tete;
	while(courant != NULL)
	{
		if(!strcmp(str,courant->cond))
		{
			ValideCondition(res,courant);
		}
		courant = courant->suiv;
	}
}


/**************************************************
**  [Fonction ValideCondition]                   **
**    Valide la condition si celle-ci est dans   **
**    les faits                                  **
**************************************************/
void ValideCondition(ST_RES *resultat,ST_COND *condition)
{
	condition->valid=True;
	resultat->nb_cond_valid = resultat->nb_cond_valid + 1;
}


/******************************************************
**  [Fonction ParcoursResultats]                     **
**    Parcours la liste chainée des resultats pour   **
**    chercher le(s) maillon(s) correspondant au     **
**    fait "actuel"                                  **
******************************************************/
void ParcoursResultats(char *str, ST_RES *pt_Tete)
{
	ST_RES *courant=pt_Tete;
	while(courant != NULL)
	{
		if(!strcmp(str,courant->res))
		{
			ValideResultat(courant);
		}
		ParcoursConditions(str,courant,courant->TeteListCond);
		courant = courant->suiv;
	}
}


/**************************************************
**  [Fonction ValideResultat]                    **
**    Valide le resultat si celui-ci est dans    **
**    les faits                                  **
**************************************************/
void ValideResultat(ST_RES *resultat)
{
	resultat->valid=True;
}


/**************************************************
**  [Fonction BoucleValidation]                  **
**    Valide le resultat si celui-ci est dans    **
**    les faits                                  **
**************************************************/
void BoucleValidation(void)
{
	ST_RES *courant=Tete_Res;
	while(courant != NULL)
	{
		if(courant->valid==False)
		{
			if(courant->nb_cond_valid == courant->nb_cond)
			{
				ValideResultat(courant);
				Tete_Faits=Creer_MaillonFaits(Tete_Faits,courant->res);
			}
		}
		courant = courant->suiv;
	}
}
